
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <asm/irq.h>
//#include <asm/arch/regs-gpio.h>
//#include <mach/regs-gpio.h>
//#include <asm/hardware.h>
//#include <mach/hardware.h>
#include <linux/device.h>
#include <linux/gpio.h>
#include <linux/rpmsg.h>
#include <linux/version.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/ioctl.h>
#include <linux/vmalloc.h>

#if LINUX_VERSION_CODE > KERNEL_VERSION(3, 3, 0)
        #include <asm/switch_to.h>
#else
        #include <asm/system.h>
#endif


#define DEVICE_NAME    "rp"    /* 设备名称 */        
static int rp_Major = 0;            /* 主设备号 */

#define MSG		"hello xiao huang! A7->M4"
#define MSG_LIMIT	10
#define RPMSG_DEV_MAX	(MINORMASK + 1)


char message_send[32752] = {"0"}; //a7 ->m4



struct instance_data 
{
	int rx_count;
};
int flag = 0;
int rflag =0;//读判断标志
volatile int file_read_buf_size;//M4发来的字符数
void *file_read_buf = NULL;
void *file_send_buf = NULL;

int _count = 0;
 struct rpmsg_device *g_rpdev;

static int rp_cb(struct rpmsg_device *rpdev, void*data, int len,void *priv, u32 src)
{

	int ret;
	struct instance_data *idata = dev_get_drvdata(&rpdev->dev);   	

	//printk(KERN_DEBUG"A7 received_rpmsg   size= %d \r\n",len);//打印m4发送过来的数据长度

	file_read_buf  = data;
	file_read_buf_size = len;
	rflag = 1;
	

	return 0;
}


static int rp_probe(struct rpmsg_device *rpdev)
{
	int ret;
	struct instance_data *idata;

	
	dev_info(&rpdev->dev, "new channel: 0x%x -> 0x%x!\n",rpdev->src, rpdev->dst);

	idata = devm_kzalloc(&rpdev->dev, sizeof(*idata), GFP_KERNEL);
	if (!idata)
		return -ENOMEM;

	dev_set_drvdata(&rpdev->dev, idata);
	g_rpdev = rpdev; 
	/* send a message to our remote processor */
	// ret = rpmsg_send(rpdev->ept, "start", strlen("start"));
	// if (ret) {
	// 	dev_err(&rpdev->dev, "rpmsg_send failed: %d\n", ret);
	// 	return ret;
	// }

	printk("A7 start:  \n");

	return 0;
}

static void rp_remove(struct rpmsg_device *rpdev)
{
	//free(file_read_buf);
	dev_info(&rpdev->dev, "rpmsg sample client driver is removed\n");
}


static struct rpmsg_device_id rpmsg_driver_sample_id_table[] = {
	{ .name	= "rpmsg-client-sample" },
	{ },
};
MODULE_DEVICE_TABLE(rpmsg, rpmsg_driver_sample_id_table);

static struct rpmsg_driver rpmsg_sample_client =
 {
	.drv.name	= KBUILD_MODNAME,
	.id_table	= rpmsg_driver_sample_id_table,
	.probe		= rp_probe,
	.callback	= rp_cb,
	.remove		= rp_remove,
};

 //struct rpmsg_driver rpmsg_sample_client   device;
//==============================================
 static  ssize_t  rp_write(struct file *file, const char * buf, size_t count, loff_t *ppos)
 {
//------用指针传，未完成,后期完善，可尝试用kmalloc
	//  copy_from_user(file_send_buf,buf,count);
	// int ret = rpmsg_send(g_rpdev->ept, file_send_buf, count);//a7给m4发送数据
    // if (ret)
	//     dev_err(&g_rpdev->dev, "rpmsg_send failed: count = %d  ret = %d\n", count,ret);
    // else
	//     printk( "send data count=%d   %d\n",count);//ret ==0



	memset(message_send,0,sizeof(message_send));
     copy_from_user(message_send,buf,count);
	if(g_rpdev == NULL)
	{
		printk("g_rpdev  is   NULL"); 
	}
	else
	{
		//printk("g_rpdev  is  not  NULL");
		int ret = rpmsg_send(g_rpdev->ept, message_send,count);//a7给m4发送数据
		if (ret)
			dev_err(&g_rpdev->dev, "rpmsg_send failed: %d\n", ret);
		// else
		// 	printk( "rp send count = %d\n",count);
	}
	//	flag = 0;
    return count;
 }


static int rp_open(struct inode *inode, struct file *file)
{
//    MOD_INC_USE_COUNT;
    printk("rp Driver Open Called!\n");
	//rpmsg_sample_probe(rpdev);
	
    return 0;
}

ssize_t rp_read(struct file *file, char * buf, size_t count, loff_t *ppos)
{

	if(rflag == 1)
	{
		copy_to_user(buf,file_read_buf,file_read_buf_size);
		printk("file_read_buf_size = %d\n",file_read_buf_size);
		// uint16_t *ptr_int = (uint16_t *) file_read_buf;    
		// int size = file_read_buf_size/2;
		// while(size--)
		// {
		// 		printk("ptr_int = %d\n",*ptr_int++);
		// }
		rflag = 0;
		return file_read_buf_size;
	}
	if(rflag ==0)
	{
		return 0;
	}
    
}

static int rp_release(struct inode *inode, struct file *file)
{
//    MOD_DEC_USE_COUNT;
    printk("rp Release Called!\n");
    return 0;
}

static long rp_ioctl( struct file *file, unsigned int cmd, unsigned long arg)
{

printk("rp into ioctll\n");
     return -EINVAL;
}

static struct file_operations rp_fops =
{
    .owner  =   THIS_MODULE,
	.open = rp_open,
    .release =  rp_release,
    .unlocked_ioctl  = rp_ioctl,
	.write = rp_write,
    .read = rp_read,
};

static struct class *rp_class;

static int __init RP_init(void)
{

    printk("RP DRIVER MODULE INIT\n");

    rp_Major = register_chrdev(0, DEVICE_NAME, &rp_fops);
    if (rp_Major < 0)
    {
        printk(DEVICE_NAME " can't register major number\n");
        return rp_Major;
    }
    printk("register RP Driver OK! Major = %d\n", rp_Major);

     rp_class = class_create(THIS_MODULE, DEVICE_NAME);
     if(IS_ERR(rp_class))
     {
         printk("Err: failed in RP class. \n");
         return -1;
     }

   int  ret = register_rpmsg_driver(&rpmsg_sample_client);
	if (ret < 0) {
		pr_err("rpmsgchr: failed to register rpmsg driver\n");
		class_destroy(rp_class);
		unregister_chrdev_region(rp_Major, RPMSG_DEV_MAX);
	}

    device_create(rp_class, NULL, MKDEV(rp_Major, 0), NULL, DEVICE_NAME);

    printk(DEVICE_NAME " initialized\n");
    return 0;
}

static void __exit RP_exit(void)
{
    printk("RP DRIVER MODULE EXIT\n");
    unregister_chrdev(rp_Major, DEVICE_NAME);
    device_destroy(rp_class, MKDEV(rp_Major, 0));
    class_destroy(rp_class);
    unregister_rpmsg_driver(&rpmsg_sample_client);
}
//module_rpmsg_driver(rpmsg_sample_client);
module_init(RP_init);
module_exit(RP_exit);

MODULE_AUTHOR("  ");        
MODULE_DESCRIPTION("XXXX ");    
MODULE_LICENSE("GPL");